#include "framelesswindow.h"
#include <QApplication>

FramelessWindow::FramelessWindow(QWidget* parent) : QWidget(parent)
{
    // 1.2去除标题栏
    this->setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
    this->installEventFilter(this);
    this->setAttribute(Qt::WA_TranslucentBackground);
}

void FramelessWindow::setTitleBarWidget(const QVector<QWidget*>& titleBarWidget)
{
    _titleBarWidget = titleBarWidget;
}

void FramelessWindow::mousePressEvent(QMouseEvent* event)
{
    if (event->button() != Qt::LeftButton) {
        return;
    }
    _leftPressed = true;

    //记录窗口左上角的坐标
    _windowPos = this->pos();
    //记录点击坐标
    _pressPos = event->globalPosition().toPoint();

    //判断当前点击位置是否在titleBar位置中
    QWidget* pressedWidget = QApplication::widgetAt(_pressPos);
    if (pressedWidget) {
        foreach (QWidget* widget, _titleBarWidget) {
            if (widget == pressedWidget) {
                _leftPressInTitle = true;
                break;
            }
        }
    }
}

void FramelessWindow::mouseMoveEvent(QMouseEvent* event)
{
    QPoint globalPos = event->globalPosition().toPoint();
    // 鼠标左键没有被点击并且允许窗口缩放，这时候移动鼠标到边界位置改变鼠标形状
    if (!_leftPressed) {
        if (this->getResizeable() && this->windowState().testFlag(Qt::WindowNoState)) {
            this->setCursorShape(globalPos);
        }
        return;
    }
    if (_location != CENTER && _resizeable) {
        QRect rect = this->rect();
        QPoint topLeft = mapToGlobal(rect.topLeft());
        QPoint bottomRight = mapToGlobal(rect.bottomRight());
        QRect rMove(topLeft, bottomRight);
        switch (_location)
        {
        case TOP:
            if (bottomRight.y() - globalPos.y() >= this->minimumHeight()) {
                rMove.setY(globalPos.y());
            }
            break;
        case BOTTOM:
            rMove.setHeight(globalPos.y() - topLeft.y());
            break;
        case LEFT:
            if (bottomRight.x() - globalPos.x() > this->minimumWidth()) {
                rMove.setX(globalPos.x());
            }
            break;
        case RIGHT:
            rMove.setWidth(globalPos.x() - topLeft.x());
            break;
        case TOP_LEFT:
            if (bottomRight.y() - globalPos.y() >= this->minimumHeight()) {
                rMove.setY(globalPos.y());
            }
            if (bottomRight.x() - globalPos.x() > this->minimumWidth()) {
                rMove.setX(globalPos.x());
            }
            break;
        case TOP_RIGHT:
            if (bottomRight.y() - globalPos.y() >= this->minimumHeight()) {
                rMove.setY(globalPos.y());
            }
            rMove.setWidth(globalPos.x() - topLeft.x());
            break;
        case BOTTOM_LEFT:
            rMove.setHeight(globalPos.y() - topLeft.y());
            if (bottomRight.x() - globalPos.x() > this->minimumWidth()) {
                rMove.setX(globalPos.x());
            }
            break;
        case BOTTOM_RIGHT:
            rMove.setHeight(globalPos.y() - topLeft.y());
            rMove.setWidth(globalPos.x() - topLeft.x());
            break;
        default:
            break;
        }
        this->setGeometry(rMove);
    }
    else {
        if (_leftPressInTitle) {
            if (this->isMaximized()) {
                // 恢复窗口大小
                float ratio = static_cast<float>(globalPos.x() - this->pos().x()) / static_cast<float>(this->width());
                qDebug() << ratio;
                qDebug() << "before width: " << this->width();
                this->setWindowState(Qt::WindowNoState);
                qDebug() << "after width: " << this->width();
                // 恢复窗口和鼠标的相对位置
                _windowPos.setX(event->pos().x() - static_cast<int>(this->width() * ratio));
                _windowPos.setY(0);
            }
            else {
                this->move(globalPos - _pressPos + _windowPos);
            }
        }
        if (!_onlyMoveByTitleBar) {
            this->move(globalPos - _pressPos + _windowPos);
        }
    }
}

void FramelessWindow::mouseReleaseEvent(QMouseEvent* event)
{
    if (event->button() != Qt::LeftButton) {
        return;
    }
    _leftPressed = false;
    _leftPressInTitle = false;
}

bool FramelessWindow::eventFilter(QObject* watched, QEvent* event)
{
    if (event->type() == QEvent::Paint) {
        static bool init = false;
        if (!init) {
            init = true;
            this->setAllWidgetMouseTracking(this);
        }
    }
    return QWidget::eventFilter(watched, event);
}

void FramelessWindow::mouseDoubleClickEvent(QMouseEvent* event)
{
    if (!this->getResizeable()) {
        return;
    }
    QWidget* widget = QApplication::widgetAt(event->globalPosition().toPoint());
    if (widget == nullptr) {
        return;
    }
    bool flag = false;
    foreach (QWidget* w, _titleBarWidget) {
        if (w == widget) {
            flag = true;
            break;
        }
    }
    if (!flag) {
        return;
    }
    this->setWindowState(this->windowState().testFlag(Qt::WindowMaximized) ? Qt::WindowNoState : Qt::WindowMaximized);
}

void FramelessWindow::setOnlyMoveByTitlebar(bool b)
{
    _onlyMoveByTitleBar = b;
}

void FramelessWindow::setResizeable(bool b)
{
    _resizeable = b;
}

bool FramelessWindow::getResizeable() const
{
    return _resizeable;
}

void FramelessWindow::setCursorShape(const QPoint& point)
{
    QRect rec = rect();
    QPoint topLeft = mapToGlobal(rec.topLeft());
    QPoint bottomRight = mapToGlobal(rec.bottomRight());
    int x = point.x();
    int y = point.y();

    if (x >= topLeft.x() && x <= topLeft.x() + _padding && y >= topLeft.y() && y <= topLeft.y() + _padding) {
        _location = TOP_LEFT;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    }
    else if (x >= bottomRight.x() - _padding && x <= bottomRight.x() && y >= topLeft.y() && y <= topLeft.y() + _padding) {
        _location = TOP_RIGHT;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    }
    else if (x >= topLeft.x() && x <= topLeft.x() + _padding && y >= bottomRight.y() - _padding && y <= bottomRight.y()) {
        _location = BOTTOM_LEFT;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    }
    else if (x >= bottomRight.x() - _padding && x <= bottomRight.x() && y >= bottomRight.y() - _padding && y <= bottomRight.y()) {
        _location = BOTTOM_RIGHT;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    }
    else if (x >= topLeft.x() + _padding && x <= bottomRight.x() - _padding && y >= topLeft.y() && y <= topLeft.y() + _padding) {
        _location = TOP;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }
    else if (x >= topLeft.x() + _padding && x <= bottomRight.x() - _padding && y >= bottomRight.y() - _padding && y <= bottomRight.y()) {
        _location = BOTTOM;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }
    else if (x >= topLeft.x() && x <= topLeft.x() + _padding && y >= topLeft.y() + _padding && y <= bottomRight.y() - _padding) {
        _location = LEFT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }
    else if (x >= bottomRight.x() - _padding && x <= bottomRight.x() && y >= topLeft.y() + _padding && y <= bottomRight.y() - _padding) {
        _location = RIGHT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }
    else {
        _location = CENTER;
        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}

void FramelessWindow::setAllWidgetMouseTracking(QWidget* widget)
{
    if (widget == nullptr) {
        return;
    }
    this->setMouseTracking(widget);
    QObjectList list = widget->children();
    foreach(QObject* object, list) {
        if (object->metaObject()->className() == QStringLiteral("QWidget")) {
            QWidget* w = static_cast<QWidget*>(object);
            w->setMouseTracking(true);
            this->setAllWidgetMouseTracking(w);
        }
    }
}
